open Ast  (* 打开 Ast 模块以引用其类型定义 *)

type ir_operand =
  | IR_Const of int
  | IR_Var of string
  | IR_Temp of int

type ir_instruction =
  | IR_Assign of ir_operand * ir_operand  (* x = y *)
  | IR_Unary of unary_op * ir_operand * ir_operand (* x = op y *)
  | IR_Binary of binary_op * ir_operand * ir_operand * ir_operand (* x = y op z *)
  | IR_Call of string * ir_operand list * ir_operand option (* x = f(args) *)
  | IR_Label of string
  | IR_Goto of string
  | IR_If of ir_operand * string (* if x goto label *)
  | IR_Return of ir_operand option
  | IR_Store of ir_operand * ir_operand (* *x = y *)
  | IR_Load of ir_operand * ir_operand (* x = *y *)

type ir_block = {
  label : string option;
  instructions : ir_instruction list;
  locals : string list;
  terminator : ir_instruction;
}

type ir_function = {
  name : string;
  params : string list;
  locals : string list;
  blocks : ir_block list;
}

type ir_program = ir_function list

let string_of_ir_operand = function
  | IR_Const n -> Printf.sprintf "Const %d" n
  | IR_Var id -> Printf.sprintf "Var %s" id
  | IR_Temp t -> Printf.sprintf "Temp %d" t

let string_of_unary_op = function
  | UPlus -> "+"
  | UMinus -> "-"
  | UNot -> "!"

let string_of_binary_op = function
  | Add -> "+"
  | Sub -> "-"
  | Mul -> "*"
  | Div -> "/"
  | Mod -> "%"
  | LT -> "<"
  | GT -> ">"
  | LE -> "<="
  | GE -> ">="
  | EQ -> "=="
  | NE -> "!="
  | And -> "&&"
  | Or -> "||"
